﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Configuration;
using System.Web.Security;
using System.Data.Odbc;
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using System.Text;
using System.Reflection;

namespace Core
{
    public class AccountImpl
    {
        static AccountImpl m_Instance = new AccountImpl();

        public static AccountImpl Instance
        {
            get { return m_Instance; }
        }

        // 缓存中的用户信息的数量
#		if DEBUG
        const int MAX_CACHE_COUNT = 2;
#		else
		const int MAX_CACHE_COUNT = 2000;
#		endif

        LinkedList<AccountInfo> m_List = new LinkedList<AccountInfo>();

        Hashtable m_UserInfoCache = new Hashtable();
        Hashtable m_UserInfoCacheByID = new Hashtable();

        object m_Lock = new object();

        IAccountStorage m_IAccountStorage = null;

        private AccountImpl()
        {
        }

        public void Init()
        {
            Configuration config = WebConfigurationManager.OpenWebConfiguration(
                HttpContext.Current.Request.ApplicationPath == "/" ? "/Lesktop" : HttpContext.Current.Request.ApplicationPath + "/Lesktop"
            );

            string accStorage = config.AppSettings.Settings["AccountStorageImpl"].Value;
            String[] accStorageInfo = accStorage.Split(new char[] { ' ' });
            Type type = Assembly.Load(accStorageInfo[0]).GetType(accStorageInfo[1]);
            ConstructorInfo ctor = type.GetConstructor(new Type[] { });
            m_IAccountStorage = ctor.Invoke(new object[] { }) as IAccountStorage;
        }

        private AccountInfo RefreshUserInfo(string userName)
        {
            string key = userName.ToUpper();

            DataRow userInfo = m_IAccountStorage.GetAccountInfo(userName);

            if (userInfo != null)
            {
                List<FriendInfo> friends = new List<FriendInfo>(), managers = new List<FriendInfo>();
                FriendInfo creator = null;
                foreach (DataRow row in m_IAccountStorage.GetFriends(userName))
                {
                    string name = row["Name"] as string;
                    DateTime renewTime = (DateTime)row["RenewTime"];
                    FriendInfo fi = new FriendInfo(name, renewTime, Convert.ToInt64(row["Relationship"]), Convert.ToInt64(row["Type"]));
                    friends.Add(fi);
                    switch (Convert.ToInt64(row["Relationship"]))
                    {
                        case 2:
                            managers.Add(fi);
                            break;
                        case 3:
                            managers.Add(fi);
                            creator = fi;
                            break;
                    }
                }


                if (m_UserInfoCache.ContainsKey(key))
                {
                    AccountInfo info = m_UserInfoCache[key] as AccountInfo;
                    info.Reset(
                        userInfo["Name"] as string,
                        userInfo["NickName"] as string,
                        Convert.ToInt64(userInfo["Key"]),
                        Convert.ToInt64(userInfo["Type"]),
                        m_IAccountStorage.GetUserRoles(userName),
                        friends.ToArray(),
                        Convert.ToInt64(userInfo["Type"]) == 1 ? managers.ToArray() : null,
                        creator,
                        userInfo["EMail"] as String,
                        userInfo["InviteCode"] as String,
                        Convert.ToInt64(userInfo["AcceptStrangerIM"]) != 0,
                        Convert.ToInt64(userInfo["MsgFileLimit"]),
                        Convert.ToInt64(userInfo["MsgImageLimit"]),
                        Convert.ToInt64(userInfo["DiskSize"]),
                        Convert.ToInt64(userInfo["IsTemp"]),
                        ((DateTime)userInfo["RegisterTime"]),
                        userInfo["HomePage"] as string,
                        userInfo["Password"] as string,
                        userInfo
                    );
                    return info;
                }
                else
                {
                    AccountInfo info = new AccountInfo(
                        userInfo["Name"] as string,
                        userInfo["NickName"] as string,
                        Convert.ToInt64(userInfo["Key"]),
                        Convert.ToInt64(userInfo["Type"]),
                        m_IAccountStorage.GetUserRoles(userName),
                        friends.ToArray(),
                        Convert.ToInt64(userInfo["Type"]) == 1 ? managers.ToArray() : null,
                        creator,
                        userInfo["EMail"] as String,
                        userInfo["InviteCode"] as String,
                        Convert.ToInt64(userInfo["AcceptStrangerIM"]) != 0,
                        Convert.ToInt64(userInfo["MsgFileLimit"]),
                        Convert.ToInt64(userInfo["MsgImageLimit"]),
                        Convert.ToInt64(userInfo["DiskSize"]),
                        Convert.ToInt64(userInfo["IsTemp"]),
                        ((DateTime)userInfo["RegisterTime"]),
                        userInfo["HomePage"] as string,
                        userInfo["Password"] as string,
                        userInfo
                    );

                    if (m_List.Count >= MAX_CACHE_COUNT)
                    {
                        AccountInfo removeInfo = m_List.First.Value;
                        m_UserInfoCache.Remove(removeInfo.Name.ToUpper());
                        m_UserInfoCacheByID.Remove(removeInfo.ID);
                        m_List.RemoveFirst();
                    }

                    m_UserInfoCache[key] = info;
                    m_UserInfoCacheByID[info.ID] = info;
                    m_List.AddLast(info.ListNode);

                    return info;
                }
            }
            else
            {
                return null;
            }
        }

        public DataRowCollection GetAllUsers()
        {
            return m_IAccountStorage.GetAllUsers();
        }

        public DataRowCollection GetAllGroups()
        {
            return m_IAccountStorage.GetAllGroups();
        }

        private AccountInfo RefreshUserInfo(Int64 id)
        {
            DataRow userInfo = m_IAccountStorage.GetAccountInfo(id);

            if (userInfo != null)
            {
                string userName = userInfo["Name"] as string;

                List<FriendInfo> friends = new List<FriendInfo>(), managers = new List<FriendInfo>();
                FriendInfo creator = null;
                foreach (DataRow row in m_IAccountStorage.GetFriends(userName))
                {
                    string name = row["Name"] as string;
                    DateTime renewTime = (DateTime)row["RenewTime"];
                    FriendInfo fi = new FriendInfo(name, renewTime, Convert.ToInt64(row["Relationship"]), Convert.ToInt64(row["Type"]));
                    friends.Add(fi);
                    switch (Convert.ToInt64(row["Relationship"]))
                    {
                        case 2:
                            managers.Add(fi);
                            break;
                        case 3:
                            managers.Add(fi);
                            creator = fi;
                            break;
                    }
                }


                if (m_UserInfoCache.ContainsKey(userName.ToUpper()))
                {
                    AccountInfo info = m_UserInfoCache[userName.ToUpper()] as AccountInfo;
                    info.Reset(
                        userInfo["Name"] as string,
                        userInfo["NickName"] as string,
                        Convert.ToInt64(userInfo["Key"]),
                        Convert.ToInt64(userInfo["Type"]),
                        m_IAccountStorage.GetUserRoles(userName),
                        friends.ToArray(),
                        Convert.ToInt64(userInfo["Type"]) == 1 ? managers.ToArray() : null,
                        creator,
                        userInfo["EMail"] as String,
                        userInfo["InviteCode"] as String,
                        Convert.ToInt64(userInfo["AcceptStrangerIM"]) != 0,
                        Convert.ToInt64(userInfo["MsgFileLimit"]),
                        Convert.ToInt64(userInfo["MsgImageLimit"]),
                        Convert.ToInt64(userInfo["DiskSize"]),
                        Convert.ToInt64(userInfo["IsTemp"]),
                        ((DateTime)userInfo["RegisterTime"]),
                        userInfo["HomePage"] as string,
                        userInfo["Password"] as string,
                        userInfo
                    );
                    return info;
                }
                else
                {
                    AccountInfo info = new AccountInfo(
                        userInfo["Name"] as string,
                        userInfo["NickName"] as string,
                        Convert.ToInt64(userInfo["Key"]),
                        Convert.ToInt64(userInfo["Type"]),
                        m_IAccountStorage.GetUserRoles(userName),
                        friends.ToArray(),
                        Convert.ToInt64(userInfo["Type"]) == 1 ? managers.ToArray() : null,
                        creator,
                        userInfo["EMail"] as String,
                        userInfo["InviteCode"] as String,
                        Convert.ToInt64(userInfo["AcceptStrangerIM"]) != 0,
                        Convert.ToInt64(userInfo["MsgFileLimit"]),
                        Convert.ToInt64(userInfo["MsgImageLimit"]),
                        Convert.ToInt64(userInfo["DiskSize"]),
                        Convert.ToInt64(userInfo["IsTemp"]),
                        ((DateTime)userInfo["RegisterTime"]),
                        userInfo["HomePage"] as string,
                        userInfo["Password"] as string,
                        userInfo
                    );

                    if (m_List.Count >= MAX_CACHE_COUNT)
                    {
                        AccountInfo removeInfo = m_List.First.Value;
                        m_UserInfoCache.Remove(removeInfo.Name.ToUpper());
                        m_UserInfoCacheByID.Remove(removeInfo.ID);
                        m_List.RemoveFirst();
                    }

                    m_UserInfoCache[userName.ToUpper()] = info;
                    m_UserInfoCacheByID[info.ID] = info;
                    m_List.AddLast(info.ListNode);

                    return info;
                }
            }
            else
            {
                return null;
            }
        }

        private String[] GetGroupManagers(string name)
        {
            return m_IAccountStorage.GetGroupManagers(name);
        }

        public bool Validate(string userId, string password)
        {
            lock (m_Lock)
            {
                return m_IAccountStorage.Validate(userId, password);
            }
        }

        public AccountInfo GetUserInfo(string user)
        {
            if (String.IsNullOrEmpty(user)) return null;
            lock (m_Lock)
            {
                string key = user.ToUpper();
                AccountInfo ai = null;
                if (m_UserInfoCache.ContainsKey(key))
                {
                    ai = m_UserInfoCache[key] as AccountInfo;
                    m_List.Remove(ai.ListNode);
                    m_List.AddLast(ai.ListNode);
                }
                else
                {
                    ai = RefreshUserInfo(user);
                }
                return ai;
            }
        }

        public AccountInfo GetUserInfo(Int64 userId)
        {
            lock (m_Lock)
            {
                AccountInfo ai = null;
                if (m_UserInfoCacheByID.ContainsKey(userId))
                {
                    ai = m_UserInfoCacheByID[userId] as AccountInfo;
                    m_List.Remove(ai.ListNode);
                    m_List.AddLast(ai.ListNode);
                }
                else
                {
                    ai = RefreshUserInfo(userId);
                }
                return ai;
            }
        }

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="name"></param>
        /// <param name="values"></param>
        public void UpdateUserInfo(string name, Hashtable values)
        {
            lock (m_Lock)
            {
                m_IAccountStorage.UpdateUserInfo(name, values);
                RefreshUserInfo(name);
            }
        }

        /// <summary>
        /// 添加好友
        /// </summary>
        /// <param name="user"></param>
        /// <param name="friend"></param>
        /// <param name="index"></param>
        public void AddFriend(string user, string friend, int index)
        {
            lock (m_Lock)
            {
                if (m_IAccountStorage.GetRelationship(user, friend) == -1)
                {
                    AddFriend(user, friend);
                }
            }
        }

        public void AddFriend(string user, string friend)
        {
            lock (m_Lock)
            {
                AccountInfo userInfo = AccountImpl.Instance.GetUserInfo(user);
                AccountInfo friendInfo = AccountImpl.Instance.GetUserInfo(friend);

                if (String.Compare(user, friend, true) != 0 && !userInfo.ContainsFriend(friend))
                {
                    m_IAccountStorage.AddFriend(user, friend);

                    RefreshUserInfo(user);
                    RefreshUserInfo(friend);

                }
            }
        }

        /// <summary>
        /// 删除好友
        /// </summary>
        /// <param name="user"></param>
        /// <param name="friend"></param>
        public void DeleteFriend(string user, string friend)
        {
            lock (m_Lock)
            {
                if (m_IAccountStorage.GetRelationship(user, friend) != -1)
                {
                    AccountInfo userInfo = GetUserInfo(user);
                    AccountInfo friendInfo = GetUserInfo(friend);

                    m_IAccountStorage.DeleteFriend(userInfo.ID, friendInfo.ID);

                    RefreshUserInfo(user);
                    RefreshUserInfo(friend);

                }
            }
        }

        public void DeleteUser(String name)
        {
            AccountInfo info = GetUserInfo(name);
            Int64 id = info.ID;
            List<String> friends = new List<string>();
            foreach (string s in info.Friends) friends.Add(s);

			m_IAccountStorage.DeleteUser(info.ID);

			try
			{
				Core.IO.Directory.Rename(String.Format("/{0}", name), String.Format("/_del_{1}_{0}", name, id));
			}
			catch
			{
			}

            foreach (string friend in friends)
            {
                RefreshUserInfo(friend);
            }
        }

        /// <summary>
        /// 删除群
        /// </summary>
        /// <param name="name"></param>
        /// <param name="creator"></param>
        public void DeleteGroup(String name, String creator)
        {
            AccountInfo info = GetUserInfo(name);
			Int64 id = info.ID;
            List<String> members = new List<string>();
			foreach (string s in info.Friends) members.Add(s);

			try
			{
				Core.IO.Directory.Rename(String.Format("/{0}", name), String.Format("/_del_{1}_{0}", name, id));
			}
			catch
			{
			}

            lock (m_Lock)
            {
                m_IAccountStorage.DeleteGroup(info.ID);

                foreach (string member in members)
                {
                    RefreshUserInfo(member);
                }
            }
        }

        public void CreateUser(String name, String nickname, String password, String email)
        {
            lock (m_Lock)
            {

                m_IAccountStorage.CreateUser(name, nickname, password, email);

                RefreshUserInfo("public");
                RefreshUserInfo("admin");
            }
        }

        public void CreateTempUser(String name, String nickname)
        {
            lock (m_Lock)
            {

                m_IAccountStorage.CreateTempUser(name, nickname);

                RefreshUserInfo("public");
                RefreshUserInfo("admin");
            }
        }

        /// <summary>
        /// 创建群
        /// </summary>
        /// <param name="creator"></param>
        /// <param name="name"></param>
        /// <param name="nickname"></param>
        public void CreateGroup(String creator, String name, String nickname)
        {
            lock (m_Lock)
            {
                m_IAccountStorage.CreateGroup(creator, name, nickname);

                RefreshUserInfo(creator);
            }
        }
    }

    public class AccountInfo : IRenderJson
    {
        object m_Lock = new object();

        private LinkedListNode<AccountInfo> m_ListNode;

        public LinkedListNode<AccountInfo> ListNode
        {
            get { return m_ListNode; }
        }

        private String m_Name, m_NickName;
        private Int64 m_ID, m_Type;
        private String[] m_Roles;
        private FriendInfo[] m_Friends;
        private FriendInfo m_Creator;
        private String m_EMail, m_InviteCode;
        private Int64 m_DiskSize;
        private bool m_IsTemp;
        private String m_Password;

        Hashtable m_FriendIndex = null;
        Hashtable m_Managers = null;

        bool m_AcceptStrangerIM;
        Int64 m_IMFileLimit, m_IMImageLimit;
        string m_HeadIMG;
        string m_Remark;

        DateTime m_RegisterTime = DateTime.Now;

        String m_HomePage = String.Empty;

        Details _detailsJson = null;

        public AccountInfo(
            String name, String nickname, Int64 id, Int64 type, String[] roles,
            FriendInfo[] friends, FriendInfo[] managers, FriendInfo creator,
            String email, String inviteCode,
            bool acceptStrangerIM, Int64 imf_limite, Int64 imimage_limit,
            Int64 diskSize, Int64 isTemp,
            DateTime registerTime,
            String homePage,
            string pwd,
            DataRow data
        )
        {
            _detailsJson = new Details(this);
            m_ListNode = new LinkedListNode<AccountInfo>(this);
            Reset(name, nickname, id, type, roles, friends, managers, creator, email, inviteCode, acceptStrangerIM, imf_limite, imimage_limit, diskSize, isTemp, registerTime, homePage, pwd, data);
        }

        public void Reset(
            String name, String nickname, Int64 id, Int64 type, String[] roles,
            FriendInfo[] friends, FriendInfo[] managers, FriendInfo creator,
            String email, String inviteCode,
            bool acceptStrangerIM, Int64 imf_limite, Int64 imimage_limit,
            Int64 diskSize, Int64 isTemp,
            DateTime registerTime,
            String homePage,
            string pwd,
            DataRow data
        )
        {
            lock (m_Lock)
            {
                m_FriendIndex = new Hashtable();
                m_Managers = new Hashtable();
                m_Name = name;
                m_NickName = nickname;
                m_ID = id;
                m_Type = type;
                m_Roles = roles;
                m_Friends = friends;
                m_Creator = creator;
                m_EMail = email;
                m_InviteCode = inviteCode;
                m_HeadIMG = data["HeadIMG"].ToString();
                m_Remark = data["Remark"].ToString();

                m_Password = pwd;

                m_AcceptStrangerIM = acceptStrangerIM;
                m_IMFileLimit = imf_limite;
                m_IMImageLimit = imimage_limit;

                m_IsTemp = (isTemp != 0);

                m_HomePage = homePage;

                m_DiskSize = diskSize;

                foreach (FriendInfo friend in friends)
                {
                    m_FriendIndex.Add(friend.Name.ToUpper(), friend);
                }

                if (managers != null)
                {
                    foreach (FriendInfo friend in managers)
                    {
                        m_Managers.Add(friend.Name.ToUpper(), friend);
                    }
                }

                m_RegisterTime = registerTime;
            }
        }

        public String[] Friends
        {
            get
            {
                lock (m_Friends)
                {
                    String[] array = new String[m_Friends.Length];
                    for (int i = 0; i < m_Friends.Length; i++) array[i] = m_Friends[i].Name;
                    return array;
                }
            }
        }

        public String[] Roles
        {
            get
            {
                lock (m_Roles)
                {
                    String[] array = new String[m_Roles.Length];
                    m_Roles.CopyTo(array, 0);
                    return array;
                }
            }
        }

        public Boolean IsTemp
        {
            get
            {
                return m_IsTemp;
            }
        }

        public String Creator
        {
            get
            {
                return m_Creator.Name;
            }
        }

        public String HeadIMG
        {
            get
            {
                return m_HeadIMG;
            }
        }

        public String Remark
        {
            get
            {
                return m_Remark;
            }
        }

        public String[] Groups
        {
            get
            {
                lock (m_Friends)
                {
                    List<String> groups = new List<string>();
                    foreach (FriendInfo friend in m_Friends)
                    {
                        if (friend.PeerType == 1) groups.Add(friend.Name);
                    }
                    return groups.ToArray();
                }
            }
        }

        public Int64 Type
        {
            get
            {
                return m_Type;
            }
        }

        public bool AcceptStrangerIM
        {
            get
            {
                return m_AcceptStrangerIM;
            }
        }

        public Int64 MsgFileLimit
        {
            get
            {
                return m_IMFileLimit;
            }
        }

        public Int64 MsgImageLimit
        {
            get
            {
                return m_IMImageLimit;
            }
        }

        public String Nickname
        {
            get
            {
                return m_NickName;
            }
        }

        public String EMail
        {
            get
            {
                return m_EMail;
            }
        }

        public String Password
        {
            get
            {
                return m_Password;
            }
        }

        public String HomePage
        {
            get
            {
                return m_HomePage;
            }
        }

        public String Name
        {
            get
            {
                return m_Name;
            }
        }

        public Int64 DiskSize
        {
            get
            {
                if (Type == 1)
                {
                    return AccountImpl.Instance.GetUserInfo(m_Creator.Name).DiskSize;
                }
                else
                {
                    return m_DiskSize * 1024 * 1024;
                }
            }
        }

        public String InviteCode
        {
            get
            {
                return m_InviteCode;
            }
        }

        public Int64 ID
        {
            get
            {
                return m_ID;
            }
        }

        public DateTime RegisterTime
        {
            get
            {
                return m_RegisterTime;
            }
        }

        public bool IsRole(string role)
        {
            foreach (string s in m_Roles)
            {
                if (s == role) return true;
            }
            return false;
        }

        public bool ContainsFriend(string name)
        {
            return m_FriendIndex.ContainsKey(name.ToUpper());
        }

        public bool ContainsMember(string name)
        {
            return m_FriendIndex.ContainsKey(name.ToUpper());
        }

        public bool IsManagedBy(string name)
        {
            return Type == 1 && m_Managers.ContainsKey(name.ToUpper());
        }

        public bool IsCreatedBy(string name)
        {
            return Type == 1 && String.Compare(name, m_Creator.Name, true) == 0;
        }

        public DateTime GetGroupMemberRenewTime(string user)
        {
            string key = user.ToUpper();
            return (m_FriendIndex[key] as FriendInfo).RenewTime;
        }

        void IRenderJson.RenderJson(StringBuilder builder)
        {
            Utility.RenderHashJson(
                builder,
                "ID", m_ID,
                "Name", m_Name,
                "Nickname", m_NickName,
                "Type", m_Type
            );
        }

        public class Details : IRenderJson
        {
            AccountInfo _info;
            public Details(AccountInfo info)
            {
                _info = info;
            }

            void IRenderJson.RenderJson(StringBuilder builder)
            {
                bool online = SessionManagement.Instance.IsOnline(_info.Name);
                if (_info.Type == 0)
                {
                    Utility.RenderHashJson(
                        builder,
                        "ID", _info.m_ID,
                        "Name", _info.m_Name,
                        "Nickname", _info.m_NickName,
                        "Type", _info.m_Type,
                        "EMail", _info.m_EMail,
                        "InviteCode", _info.m_InviteCode,
                        "HeadIMG", _info.m_HeadIMG,
                        "HomePage", _info.m_HomePage,
                        "Remark", _info.m_Remark,
						"State", online ? "Online" : "Offline",
                        "IsTemp", _info.IsTemp
                    );
                }
                else
                {
                    Utility.RenderHashJson(
                        builder,
                        "ID", _info.m_ID,
                        "Name", _info.m_Name,
                        "Nickname", _info.m_NickName,
                        "Type", _info.m_Type,
                        "EMail", _info.m_EMail,
                        "InviteCode", _info.m_InviteCode,
                        "HeadIMG", _info.m_HeadIMG,
                        "HomePage", _info.m_HomePage,
                        "Remark", _info.m_Remark,
                        "IsTemp", _info.IsTemp
                    );
                }
            }
        }

        public Details DetailsJson
        {
            get { return _detailsJson; }
        }
    }

    public class FriendInfo
    {
        public String Name;
        public DateTime RenewTime;
        public Int64 Relationthip;
        public Int64 PeerType;

        public FriendInfo(string name, DateTime renewTime, Int64 relationthip, Int64 peerType)
        {
            Name = name;
            RenewTime = renewTime;
            Relationthip = relationthip;
            PeerType = peerType;
        }
    }
}
